/**********************************************************
 * ActionScript Development Tool 
 * Copyright (C) 2005 asdt.org 
 * 
 * http://www.asdt.org
 * http://sourceforge.net/projects/aseclipseplugin/
 *
 * This program is free software; 
 * you can redistribute it and/or modify it under the terms of 
 * the GNU General Public License as published by the 
 * Free Software Foundation; either version 2 of the License, 
 * or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License 
 * along with this program; if not, write to the 
 * Free Software Foundation, Inc., 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 
 * 
 **********************************************************/

package ca.scotthyndman.as2haxe.dom;

import java.util.ArrayList;
import java.util.List;

import ca.scotthyndman.as2haxe.dom.binding.IBinding;
import ca.scotthyndman.as2haxe.dom.visitor.IVisitor;

/**
 * Represents an import statement.
 * 
 * @author Nico Zimmermann
 * @author Scott Hyndman (as2haxe)
 */
public class ASImportDeclaration extends ASTNode {
	/**
	 * The "name" structural property of this node type.
	 * 
	 * @since 3.0
	 */
	public static final ASChildPropertyDescriptor NAME_PROPERTY = new ASChildPropertyDescriptor(
			ASImportDeclaration.class, "name", ASQualifiedName.class, true);

	/**
	 * The "onDemand" structural property of this node type.
	 * 
	 * @since 3.0
	 */
	public static final ASSimplePropertyDescriptor ON_DEMAND_PROPERTY = new ASSimplePropertyDescriptor(
			ASImportDeclaration.class, "onDemand", boolean.class, true);

	/**
	 * A list of property descriptors (element type:
	 * {@link ASPropertyDescriptor}), or null if uninitialized.
	 */
	private static final List<ASPropertyDescriptor> PROPERTY_DESCRIPTORS;

	static {
		List<Object> properyList = new ArrayList<Object>(3);
		createPropertyList(ASImportDeclaration.class, properyList);
		addProperty(NAME_PROPERTY, properyList);
		addProperty(ON_DEMAND_PROPERTY, properyList);
		PROPERTY_DESCRIPTORS = reapPropertyList(properyList);
	}

	/**
	 * Returns a list of structural property descriptors for this node type.
	 * Clients must not modify the result.
	 * 
	 * @return a list of property descriptors
	 */
	public static List<ASPropertyDescriptor> propertyDescriptors() {
		return PROPERTY_DESCRIPTORS;
	}

	//
	// ======== MEMBERS
	//

	private ASQualifiedName importName;

	private boolean onDemand = false;

	//
	// ======== CONSTRUCTION
	//

	public ASImportDeclaration(AST ast) {
		super(ast);
	}

	//
	// ======== GETTERS / SETTERS
	//

	/**
	 * Returns whether this import declaration is an on-demand or a single-type
	 * import.
	 * 
	 * @return <code>true</code> if this is an on-demand import, and
	 *         <code>false</code> if this is a single type import
	 */
	public boolean isOnDemand() {
		return onDemand;
	}

	/**
	 * Sets whether this import declaration is an on-demand or a single-type
	 * import.
	 * 
	 * @param onDemand
	 *            <code>true</code> if this is an on-demand import, and
	 *            <code>false</code> if this is a single type import
	 */
	public void setOnDemand(boolean onDemand) {
		preValueChange(ON_DEMAND_PROPERTY);
		this.onDemand = onDemand;
		postValueChange(ON_DEMAND_PROPERTY);
	}

	/**
	 * Returns the name imported by this declaration.
	 * <p>
	 * For a regular on-demand import, this is the name of a package. For a
	 * static on-demand import, this is the qualified name of a type. For a
	 * regular single-type import, this is the qualified name of a type.
	 * </p>
	 * 
	 * @return the imported name node
	 */
	public ASQualifiedName getName() {
		return importName;
	}

	/**
	 * Sets the name of this import declaration to the given name.
	 * <p>
	 * For a regular on-demand import, this is the name of a package. For a
	 * static on-demand import, this is the qualified name of a type. For a
	 * regular single-type import, this is the qualified name of a type.
	 * </p>
	 * 
	 * @param name
	 *            the new import name
	 * @exception IllegalArgumentException
	 *                if:
	 *                <ul>
	 *                <li>the node belongs to a different AST</li>
	 *                <li>the node already has a parent</li>
	 *                </ul>
	 */
	public void setName(ASQualifiedName name) {
		if (name == null) {
			throw new IllegalArgumentException();
		}
		ASTNode oldChild = this.importName;
		preReplaceChild(oldChild, name, NAME_PROPERTY);
		this.importName = name;
		postReplaceChild(oldChild, name, NAME_PROPERTY);
	}

	//
	// ======== INTERNAL GETTER / SETTER
	//

	/*
	 * (omit javadoc for this method) Method declared on ASTNode.
	 */
	final boolean internalGetSetBooleanProperty(
			ASSimplePropertyDescriptor property, boolean get, boolean value) {
		if (property == ON_DEMAND_PROPERTY) {
			if (get) {
				return isOnDemand();
			} else {
				setOnDemand(value);
				return false;
			}
		}

		// allow default implementation to flag the error
		return super.internalGetSetBooleanProperty(property, get, value);
	}

	/*
	 * (omit javadoc for this method) Method declared on ASTNode.
	 */
	final ASTNode internalGetSetChildProperty(
			ASChildPropertyDescriptor property, boolean get, ASTNode child) {
		if (property == NAME_PROPERTY) {
			if (get) {
				return getName();
			} else {
				setName((ASQualifiedName) child);
				return null;
			}
		}
		// allow default implementation to flag the error
		return super.internalGetSetChildProperty(property, get, child);
	}
	
	// ===== BINDINGS

	/**
	 * Returns the binding linked to this method call.
	 */
	public IBinding resolveBinding() {
		return getAST().getBindingManager().resolveImportBinding(this);
	}

	//
	// ======== OVERRIDES
	//

	/**
	 * @see ca.scotthyndman.as2haxe.dom.visitor.IVisitable#accept(ca.scotthyndman.as2haxe.dom.visitor.IVisitor,
	 *      boolean)
	 */
	public void accept(IVisitor as2Visitor, boolean visitChilds) {
		visitChilds = as2Visitor.visit(this);
	}

	/**
	 * Returns a string representation of the import declaration.
	 */
	public String toString() {
		return "import " + getName().toString();
	}
}